#! /usr/bin/env python
# -*- coding: utf-8 -*-

# *************************************************************
#     Filename @  utils.py
#       Author @  Huoty
#  Create date @  2016-07-14 20:36:27
#  Description @  utils
# *************************************************************

import re
import time
import random
import datetime
import contextlib
from urllib.parse import urlparse

import requests
from retrying import retry


cur_year = int(time.strftime("%Y", time.localtime()))


def is_even(x):
    return False if x & 1 else True


def is_odd(x):
    return bool(x & 1)


def convert_int(x):
    try:
        return int(x)
    except ValueError:
        return 0


def is_zhcn(uchar):
    if uchar >= u'\u4e00' and uchar <= u'\u9fa5':
        return True
    return False


def str_to_date(s):
    """convert str to datetime.date

    +--------------+-------------+
    | Good_formats | Bad_formats |
    +--------------+-------------+
    |  2016-10-01  |   16-10-01  |
    |  2016-10-1   |   16-10-1   |
    |  2016-1-1    |   16-1-1    |
    |  2016/10/01  |   16/10/01  |
    |  2016/10/1   |   16/10/1   |
    |  2016/1/1    |   16/1/1    |
    |  20161001    |   161001    |
    |  01-01       |   201671    |
    |  10-1        |   1671      |
    |  1-1         |   2016711   |
    |  01/01       |   2016071   |
    |  10/1        |   16101     |
    |  1/1         |   16711     |
    |  0101        |   110       |
    |              |   011       |
    |              |   71        |
    +--------------+-------------+
    """
    str_date_width = len(s)
    if (is_odd(str_date_width) and not re.search(r"[/-]{1}", s)) or \
            str_date_width > 10 or str_date_width < 2:
        raise Exception("%s is bad date formats!" % s)

    if re.search(r"[/-]{1}", s):
        try:
            st = map(int, s.split('-') if '-' in s else s.split('/'))
        except ValueError:
            raise Exception("%s is bad date formats!" % s)

        st = list(st)  # Compatible with python 3
        st_len = len(st)
        if st_len not in (2, 3):
            raise Exception("%s is bad date formats!" % s)
        if st_len == 2:
            st = [cur_year] + st

        return datetime.date(*st)
    elif str_date_width == 8:
        return datetime.date(*map(int, [s[:4], s[4:6], s[6:]]))
    elif str_date_width == 4:
        return datetime.date(*map(int, [cur_year, s[:2], s[2:]]))
    else:
        raise Exception("%s is bad date formats!" % s)


@retry(stop_max_attempt_number=5, wait_exponential_multiplier=1000)
def request_resources(url, params=None, method="GET"):
    # Not show warings
    try:
        from requests.packages.urllib3.exceptions import (
            SNIMissingWarning,
            InsecureRequestWarning,
            InsecurePlatformWarning
        )

        requests.packages.urllib3.disable_warnings(SNIMissingWarning)
        requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
        requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
    except ImportError:
        pass

    with contextlib.closing(requests.get(url, params=params, verify=False) \
            if method == "GET" else requests.post(url, data=params, verify=False)) as req:
        req.raise_for_status()
        body = req.content.decode('utf-8')

    return body


class Colorizing(object):
    colors = {
        'none': "",
        'default': "\033[0m",
        'bold': "\033[1m",
        'underline': "\033[4m",
        'blink': "\033[5m",
        'reverse': "\033[7m",
        'concealed': "\033[8m",

        'black': "\033[30m",
        'red': "\033[31m",
        'green': "\033[32m",
        'yellow': "\033[33m",
        'blue': "\033[34m",
        'magenta': "\033[35m",
        'cyan': "\033[36m",
        'white': "\033[37m",

        'on_black': "\033[40m",
        'on_red': "\033[41m",
        'on_green': "\033[42m",
        'on_yellow': "\033[43m",
        'on_blue': "\033[44m",
        'on_magenta': "\033[45m",
        'on_cyan': "\033[46m",
        'on_white': "\033[47m",

        'beep': "\007",
    }

    def __call__(self, s, color=None):
        if color in self.colors:
            return "{0}{1}{2}".format(
                self.colors[color],
                s,
                self.colors['default'])
        else:
            return s


class Throttle(object):

    def __init__(self, delay=None):
        self.delay = delay
        self._domains = {}

    def __call__(self, url):
        domain = urlparse(url).netloc
        last_accessed = self._domains.get(domain)

        delay = self.delay if self.delay else random.randint(1, 20)
        now = datetime.datetime.now

        if delay > 0 and last_accessed is not None:
            sleep_secs = delay - (now() - last_accessed).seconds

            if sleep_secs > 0:
                time.sleep(sleep_secs)

        self._domains[domain] = now()
